﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using RayDen.Library.Core;
using RayDen.Library.Core.Primitives;
using RayDen.RayEngine.Core.Interface;
using RayDen.RayEngine.Core.Types;

namespace RayDen.RayEngine.Engines.MCMC.PSS
{
    public class PsMltSampler : ISampler
    {

        public static int PreviewPasses = 16;
        public static int IterationPerPass = 16;
        public static int MagicValue2 = 16;

        private readonly object b_lock = new object();

        public float LargeStepProbability = 0.3f;
        public int MaxSampleDimension = 14 * 10;
        public int BurnInPaths = 100000;
        public int MaxMutations = 10000;

        int currentSampleScreenX, currentSampleScreenY, currentSubSampleIndex;

        private IRandomProvider rnd;
        private int pass;
        public uint burnPaths;
        private ulong totalSamples;


        public RgbSpectrum Bt,B;

        internal int sceneMaxPathDepth, screenWidth, screenHeight, screenStartLine;

        public PsMltSampler()
        {
            this.rnd = new FastRandom();
        }

        public bool BurnInPhase
        {
            get
            {
                if (burnPaths >= BurnInPaths - 1 && burnPaths < BurnInPaths)
                {
                    Console.WriteLine("Burndown complete");
                }
                return burnPaths<BurnInPaths;
            }
        }

        public Sample GetSample(Sample prevSample = null)
        {
            totalSamples++;

            if (prevSample == null)
            {
                var ns = new PsSample(this);

                ns.imageX = ns.GetLazyValue() * screenWidth;
                ns.imageY = ns.GetLazyValue() * screenHeight;
                ns.pass = pass;
                return ns;
            }
            prevSample.imageX = prevSample.GetLazyValue() * screenWidth;
            prevSample.imageY = prevSample.GetLazyValue() * screenHeight;
            
            prevSample.pass = pass;
            (prevSample as PsSample).MutationsCount = 0;
            (prevSample as PsSample).CurrentDim = 0;
            (prevSample as PsSample).MaxDimPrev = 0;

            return prevSample;
        }



        public void AddContribution(ref RgbSpectrum c)
        {
            //lock (b_lock)
            {
                Bt += c;
                burnPaths++;
                B = Bt/(float) burnPaths;
            }
        }

        public float GetLazyValue(Sample sample)
        {
            return (sample as PsSample).GetLazyValue();
        }

        public float GetLDValue(Sample sample)
        {
            throw new NotImplementedException();
        }

        public float NextFloat()
        {
            return rnd.NextFloat();
        }

        public void Accept(PsSample sample)
        {
            for (int i = 0; i < sample.CurrentDim; i++)
            {
                sample.PrevSamples[i] = sample.sampleData[i];
            }
            sample.MaxDimPrev = sample.CurrentDim;
            sample.CurrentDim = 0;
        }

        public void Reject(PsSample sample)
        {
            sample.CurrentDim = 0;
        }

        public void Init(int p1, int p2)
        {
            screenWidth = Math.Max(screenWidth, p1);
            screenHeight = Math.Max(screenHeight, p2);
        }

        public int GetPass()
        {
            return pass;
        }

        public int Width
        {
            get { return screenWidth; }
        }

        public int Height
        {
            get { return screenHeight; }
        }

        public long TotalSamples
        {
            get
            {
                return (long)totalSamples;
            }
            set
            {
                totalSamples = (ulong)value;
            }
        }

        public float GetLazyValue(Sample sample, int index)
        {
            throw new NotImplementedException();
        }
    }
}
